#pragma once
#include <string>
#include <MQ_Virtual_Engine/exchangeClass.hpp>
#include <unordered_map>
#include <Common/sqliteHelper.hpp>
#include <Common/FileHelper.hpp>
#include <mutex>
namespace MY_MQ
{
  class BindInfo
  {
  public:
    using self_ptr = std::shared_ptr<BindInfo>;
    std::string _ExchangeName;
    std::string _Queue_Name;
    std::string _BindingKey;
    bool _durable; // 是否持久化
    BindInfo(std::string ExchangeName, std::string QueueName, std::string BindingKey, bool durable)
        : _ExchangeName(ExchangeName), _Queue_Name(QueueName), _BindingKey(BindingKey), _durable(durable)
    {
    }
    // 设计一个图，方便每一个消息队列来找到自己归属哪个绑定队列
  };
  using MsgQueue_BindingMap = std::unordered_map<std::string, BindInfo::self_ptr>;
  using Exchange_BindingMap = std::unordered_map<std::string, MsgQueue_BindingMap>;
  const std::string BindInfoSqlite_table = "./config/BindInfoSqlite_table.string";
  class BindInfoBuilder
  {
    sqliteHelper _db;
    std::string _tableName;

  public:
    BindInfoBuilder(const std::string &db)
    {
      std::filesystem::create_directories(std::filesystem::path(db).parent_path());
      _db.open(db);
      _tableName = std::filesystem::path(BindInfoSqlite_table).stem().string();
      createTable();
    }

    // create table if not exists BindInfoSqlite_table(
    //     exchange_name varchar(255) not null,
    //     queue_name varchar(255) not null,
    //     binding_key varchar(255) not null,
    //     durable int not null
    // )
    void createTable()
    {
      std::string createTableSql;
      Filehelper(BindInfoSqlite_table).read_as_string(createTableSql);
      if (false == _db.exec(createTableSql))
      {
        loge("create table failed");
        abort();
      }
    }
    void removeTable()
    {
      if (false == _db.exec("drop table if exists " + _tableName))
      {
        loge("drop table failed");
      }
    }
    bool insert(const BindInfo &bindInfo)
    {
      std::string insertSql = "insert into " + _tableName + " values('" + bindInfo._ExchangeName + "','" + bindInfo._Queue_Name + "','" + bindInfo._BindingKey + "'," + std::to_string(bindInfo._durable) + ")";
      return _db.exec(insertSql);
    }

    bool remove(const std::string &exchangeName, const std::string &queueName)
    {
      std::string removeSql = "delete from " + _tableName + " where exchange_name='" + exchangeName + "' and queue_name='" + queueName + "'";
      return _db.exec(removeSql);
    }
    void removeExchangeBindings(const std::string &exchangeName)
    {
      std::string removeSql = "delete from " + _tableName + " where exchange_name='" + exchangeName + "'";
      _db.exec(removeSql);
    }
    void removeQueueBindings(const std::string &queueName)
    {
      std::string removeSql = "delete from " + _tableName + " where queue_name='" + queueName + "'";
      _db.exec(removeSql);
    }
    Exchange_BindingMap recovery()
    {
      Exchange_BindingMap result;
      std::string selectSql = "select * from " + _tableName;
      auto res = _db.exec(selectSql, sqlcallback, &result);
      return result;
    }

  private:
    static int sqlcallback(void *data, int argc, char **argv, char **azColName)
    {
      auto &result = *(Exchange_BindingMap *)data;
      BindInfo::self_ptr bip = std::make_shared<BindInfo>(argv[0], argv[1], argv[2], std::string(argv[3]) == std::string("1"));
      result[argv[0]][argv[1]] = bip;
      return 0;
    }
  };
  class BindInfoManager
  {
  public:
    using self_ptr = std::shared_ptr<BindInfoManager>;

    BindInfoManager(const std::string &db)
        : _builder(db)
    {
      _exchangeBindingMap = _builder.recovery();
    }
    // 这个交换机和队列绑定的持久化要求两者都是持久化绑定才有这个要求
    // 也就是传入参数时 exchange.durable 和 queue.durable 都为true
    bool Bind(const std::string &exchangeName, const std::string &queueName, const std::string &bindingKey, bool durable)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end() && it->second.find(queueName) != it->second.end())
      {
        // 绑定关系已经成立，无需再绑定
        _builder.insert(*it->second[queueName]);
        return true;
      }
      BindInfo::self_ptr bip = std::make_shared<BindInfo>(exchangeName, queueName, bindingKey, durable);
      _exchangeBindingMap[exchangeName][queueName] = bip;
      return _builder.insert(*bip);
    }
    bool Unbind(const std::string &exchangeName, const std::string &queueName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end() && it->second.find(queueName) != it->second.end())
      {
        _exchangeBindingMap[exchangeName].erase(queueName);
        return _builder.remove(exchangeName, queueName);
      }
      return true;
    }
    void RemoveExchangeBindings(const std::string &exchangeName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end())
      {
        _exchangeBindingMap.erase(exchangeName);
        _builder.removeExchangeBindings(exchangeName);
      }
    }
    void RemoveQueueBindings(const std::string &queueName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      for (auto &it : _exchangeBindingMap)
      {
        if (it.second.find(queueName) != it.second.end())
        {
          it.second.erase(queueName);
          _builder.remove(it.first, queueName);
        }
      }
    }
    // 如果你请求的 交换机不存在，会返回空的 MsgQueue_BindingMap
    // 如果你输入的交换机不存在本数据库，那么将返回空的 MsgQueue_BindingMap
    // 而代码正常运行下，不会存在exchangeName存在，但是exchangeBindingMap中不存在的情况
    MsgQueue_BindingMap GetQueueBindingMap(const std::string &exchangeName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end())
      {
        return it->second;
      }
      logw("GetQueueBindingMap: exchange {} not found", exchangeName);
      return MsgQueue_BindingMap();
    }
    BindInfo::self_ptr GetBindInfo(const std::string &exchangeName, const std::string &queueName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end() && it->second.find(queueName) != it->second.end())
      {
        return it->second[queueName];
      }
      return nullptr;
    }
    bool exist(const std::string &exchangeName, const std::string &queueName)
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _exchangeBindingMap.find(exchangeName);
      if (it != _exchangeBindingMap.end() && it->second.find(queueName) != it->second.end())
      {
        return true;
      }
      return false;
    }
    std::size_t size()
    {
      std::lock_guard<std::mutex> lock(_mutex);
      return _exchangeBindingMap.size();
    }
    void clear()
    {
      std::lock_guard<std::mutex> lock(_mutex);
      _exchangeBindingMap.clear();
      _builder.removeTable();
    }
    // 此时只需要清空当前绑定的即可
    void clearTmp()
    {
      std::lock_guard<std::mutex> lock(_mutex);
      for (auto &it : _exchangeBindingMap)
      {
        for (auto &it2 : it.second)
        {
          if (it2.second->_durable == false)
          {
            _builder.remove(it.first, it2.first);
          }
        }
      }
      _exchangeBindingMap.clear();
    }

  private:
    Exchange_BindingMap _exchangeBindingMap;
    BindInfoBuilder _builder;
    std::mutex _mutex;
  };
};